#include "Game.h"
#include "Player.h"
#include "Board.h"
#include "PropertyList.h"
#include "Deck.h"
#include "ConsoleBox.h"
#include <time.h>

void Game::Init()
{
	srand(time(0));
	properties = new PropertyList();
	communityDeck = new Deck();
	chanceDeck = new Deck();
	players = new Player[4];
	board = new Board(24, 0);
	cBox = new ConsoleBox(58, 14, 20, 10);

	// Load all the file-based stuff
	properties->loadFromFile("Properties.txt");
	communityDeck->loadFromFile("CommunityChest.txt");
	chanceDeck->loadFromFile("Chance.txt");
	board->loadFromFile("Board.txt", "BoardSpaces.txt", properties);

	cBox->AddString("Welcome to Monopoly!\nPlayer 1, press R\nto roll the dice!");

	for(int i = 0; i < NUM_PLAYERS; i++)
	{
		players[i].Init(this, i + 3, i);
	}

	dice[0] = new RandomDie(1, 7);
	dice[1] = new RandomDie(12, 7);

	curPlayer = 0;
	offsX = offsY = 0;	
	waiting = false;

	// Do this just to get it on the screen on startup
	dice[0]->Roll(1);
	dice[1]->Roll(1);

	m_gameState = G_PLAYING;
}

void Game::MoveCamera()
{
	int moveCam;
	
	// Check each player
	for(int i = 0; i < NUM_PLAYERS; i++)
	{
		// Keep moving the camera until the player is in view
		do
		{
			moveCam = players[i].CheckInBoundaries(board->getPosX(), board->getPosY(), offsX, offsY, false);

			if(i == curPlayer)
			{
				switch(moveCam)
				{
					case MOVE_CAM_LEFT: MoveCamLeft(14); break;
					case MOVE_CAM_RIGHT: MoveCamRight(14); break;
					case MOVE_CAM_UP: MoveCamUp(9); break;
					case MOVE_CAM_DOWN: MoveCamDown(9); break;
				}
			}
			
		}while(moveCam != 1 && i == curPlayer);
	}
}
void Game::Update()
{
	int bankruptPlayers = 0;

	for(int i = 0; i < NUM_PLAYERS; i++)
	{
		bankruptPlayers += players[i].isBankrupt();

		if(!players[i].isBankrupt())
			players[i].Update();
	}

	if(bankruptPlayers == NUM_PLAYERS-1)
		for(int i = 0; i < NUM_PLAYERS; i++)
			if(!players[i].isBankrupt())
			{
				// Draw one last time
				Draw();

				// Let 'em know who won
				char tmp[16];
				cBox->Clear();
				sprintf_s(tmp, "Player %d wins!", i+1);
				cBox->AddString(tmp);
				players[i].StupidHack();

				// Game over!
				Quit();
			}

	MoveCamera();
}

void Game::MoveCamLeft(int a_move)
{
	offsX -= a_move;
	if(offsX < 0)
		offsX = 0;
}

void Game::MoveCamRight(int a_move)
{
	offsX += a_move;
	if(offsX > board->getWidth() - VIEW_WIDTH)
		offsX = board->getWidth() - VIEW_WIDTH;
}

void Game::MoveCamUp(int a_move)
{
	offsY -= a_move;
	if(offsY < 0)
		offsY = 0;
}

void Game::MoveCamDown(int a_move)
{
	offsY += a_move;
	if(offsY > board->getHeight() - VIEW_HEIGHT)
		offsY = board->getHeight() - VIEW_HEIGHT;
}

void Game::Input(int a_input)
{
	int roll1 = 0;
	int roll2 = 0;

	switch(a_input)
	{
	case 'q':
		Quit();
		break;
	case '6':
		players[curPlayer].RollLogic(1, 6);
		break;
	case '1':
		players[curPlayer].RollLogic(1, 0);
		break;
	case '4':
		players[curPlayer].RollLogic(3, 1);
		break;
	case 'r': 
		// Can't roll the dice while waiting
		if(waiting)
			break;

		waiting = true;
		// Roll the dice
		roll1 = dice[0]->Roll(25);
		roll2 = dice[1]->Roll(25);
		
		players[curPlayer].RollLogic(roll1, roll2);
		break;

	case 't':
		ClearScreen();
		m_gameState = G_TRADING;
		// no break here on purpose
	default: // Handle everything else by the player

		players[curPlayer].handleInput(a_input);
		break;
	}
}

void Game::Draw()
{
	if(m_gameState == G_PLAYING)
	{
		// Check if any of the players have moved
		bool dirty = false;
		for(int i = 0; i < NUM_PLAYERS; i++)
			if(players[i].isMoving())
				dirty = true;

		// Only redraw players/board if they need to be.
		if(dirty)
		{ 
			// Draw a portion of the board
			board->drawPortion(offsX, offsY);

			// Draw all the players
			for(int i = 0; i < NUM_PLAYERS; i++)
			{
				if(players[i].isBankrupt())
					continue;
				
				// Draw
				players[i].CheckInBoundaries(board->getPosX(), board->getPosY(), offsX, offsY, true);
			}

			// Draw the info for the space that the current player is on
			board->drawSpace(players[curPlayer].getSpace());
		}

		// Draw each player's money
		DrawMoney();

		// Draw the current player's inventory
		players[curPlayer].DrawInventory();
	}
	else // Trading
	{
		players[0].trade(&players[1]);
	}

	// Draw the console
	cBox->Draw();
}

void Game::DrawMoney()
{
	const int boxX = 1;
	const int boxY = 16;
	const int width = 20;
	const int height = NUM_PLAYERS+3;
	static int lastMoney[NUM_PLAYERS];
	bool changed = false;

	// Check if money has changed hands
	for(int i = 0; i < NUM_PLAYERS; i++)
	{
		if(lastMoney[i] != players[i].getMoney())
		{
			lastMoney[i] = players[i].getMoney();
			changed = true;
		}
	}

	// If money hasn't changed hands, don't draw.
	if(!changed)
		return;

	// Draw the top line
	gotoXY(boxX+1, boxY);
	printf("-------Money--------");

	// Draw the outer box
	for(int y = 1 ; y < height; y++)
	{
		// Left line
		gotoXY(boxX, boxY+y);
		_putch('|');

		// Empty space
		for(int x = 0; x < width; x++)
			_putch(' ');

		// Right line
		_putch('|');
	}

	// Draw the bottom line
	gotoXY(boxX+1, boxY+height);
	printf("--------------------");

	// Draw the money values
	for(int y = 0; y < NUM_PLAYERS; y++)
	{
		gotoXY(boxX+2, boxY+y+1);
		if(players[y].isBankrupt())
			printf("Player %d: BANKRUPT", y+1);
		else
			printf("Player %d: $%*d", y+1, 5, players[y].getMoney());
	}
}

void Game::Quit()
{
	gotoXY(0, 24);
	exit(0);
}

void Game::NextPlayer()
{
	char tmp[256];

	// Keep going 'til you find an active player.
	do
	{
		curPlayer++;
		if(curPlayer >= NUM_PLAYERS)
			curPlayer = 0;
	}while(players[curPlayer].isBankrupt());

	sprintf_s(tmp, "Player %d's turn.\nPress R to\nroll the dice.\nPress B to\nbuy a house.\nPress S to\nsell a house.\nPress M to\nmortgage a property.", curPlayer+1);
	cBox->AddString(tmp);
}

int Game::searchSpace(char* a_search, int a_start)
{
	return board->searchSpace(a_search, a_start);
}

Space* Game::getSpace(int a_space) { return board->getSpace(a_space); }

Card* Game::pickupChanceCard() { return chanceDeck->pickUpCard(); }

Card* Game::pickupCommunityChestCard() { return communityDeck->pickUpCard(); }
